//
// Copyright (c) 2011 Alex Nesterenko
//

#include "nane/core/types.h"
#include "nane/core/crt/DynamicModule.h"
#include <dlfcn.h>
#include <string>
#include <unistd.h>
#include <vector>

namespace nane
{
    ////////////////////////////////////////////////////////////////////////////////////////////////
    ModuleHandle* ModuleHandle::s_staticHandle = reinterpret_cast<ModuleHandle*>(-1);
    ////////////////////////////////////////////////////////////////////////////////////////////////
    ModuleHandle* DynamicModule::loadModule( const char* _moduleName )
    {
        ModuleHandle* handle = static_cast<ModuleHandle*>(::dlopen(_moduleName, RTLD_LAZY));
        if( handle == NULL )
        {
            std::string moduleName = _moduleName;
            moduleName += ".so";
            handle = static_cast<ModuleHandle*>(::dlopen(moduleName.c_str(), RTLD_LAZY));
        }
        if( handle == NULL )
        {
            long int bufSize = ::pathconf(".", _PC_PATH_MAX);
            std::vector<char> buf;
            buf.resize(bufSize);
            ::getcwd(&(buf[0]), bufSize);
            std::string moduleName(&(buf[0]));
            moduleName.push_back('/');
            moduleName += _moduleName;
            handle = static_cast<ModuleHandle*>(::dlopen(moduleName.c_str(), RTLD_LAZY));
            if( handle == NULL )
            {
                moduleName += ".so";
                handle = static_cast<ModuleHandle*>(::dlopen(moduleName.c_str(), RTLD_LAZY));
            }
        }

        return handle;
    }
    ////////////////////////////////////////////////////////////////////////////////////////////////
    void* DynamicModule::getFunction( ModuleHandle* _handle, const char* _functionName )
    {
        return ::dlsym(static_cast<void*>(_handle), _functionName);
    }
    ////////////////////////////////////////////////////////////////////////////////////////////////
    void DynamicModule::unloadModule( ModuleHandle* _handle )
    {
        if( _handle != NULL )
        {
            ::dlclose(static_cast<void*>(_handle));
        }
    }
    ////////////////////////////////////////////////////////////////////////////////////////////////
}   // namespace nane
